
package com.be.beadmin.quality.impl;

import cn.hutool.core.util.ObjectUtil;
import com.be.beadmin.basicData.dto.output.UserEx;
import com.be.beadmin.basicData.service.UserService;
import com.be.beadmin.common.entity.PageEntity;
import com.be.beadmin.common.exception.BeadminException;
import com.be.beadmin.common.utils.JpaQueryBuilder;
import com.be.beadmin.common.utils.JpaSortBuilder;
import com.be.beadmin.product.entity.ProductManufactInfor;
import com.be.beadmin.product.entity.WorkOrderInfor;
import com.be.beadmin.product.repository.ProductManufactInforRepository;
import com.be.beadmin.product.repository.WorkOrderInforRepository;
import com.be.beadmin.product.service.ProductManufactInforService;
import com.be.beadmin.project.entity.BatchPlan;
import com.be.beadmin.project.entity.BatchProduct;
import com.be.beadmin.project.entity.Info;
import com.be.beadmin.project.repository.BatchPlanRepository;
import com.be.beadmin.project.repository.BatchProductRepository;
import com.be.beadmin.project.repository.InfoRepository;
import com.be.beadmin.quality.dto.input.*;
import com.be.beadmin.quality.dto.output.InspectionTaskEx;
import com.be.beadmin.quality.entity.*;
import com.be.beadmin.quality.mapper.InspectionTaskMapper;
import com.be.beadmin.quality.mapper.InspectionTaskMapperEx;
import com.be.beadmin.quality.repository.*;
import com.be.beadmin.quality.service.*;
import com.be.beadmin.service.util.DateUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.function.Function;

/**
* @description 服务实现
* @author zjm
* @date 2023-05-28
**/
@Service
@RequiredArgsConstructor
public class InspectionTaskServiceImpl implements InspectionTaskService {

    @Autowired
    private InspectionTaskRepository inspectionTaskRepository;

    @Autowired
    private ProductManufactInforRepository productManufactInforRepository;
    @Autowired
    private ProductSelfCheckInforRepository productSelfCheckInforRepository;

    @Autowired
    private ProductManufactInforService productManufactInforService;
    @Autowired
    private  InspectionTaskMapper inspectionTaskMapper;
    @Autowired
    private  InspectionTaskMapperEx inspectionTaskExMapper;
    @Autowired
    private WorkOrderInforRepository workOrderInforRepository;
    @Autowired
    private InfoRepository infoRepository;

    @Autowired
    private InspectionTemplateRepository inspectionTemplateRepository;

    @Autowired
    private InspectionTemplateService inspectionTemplateService;
    @Autowired
    private InspectionTemplateMasterItemRepository inspectionTemplateMasterItemRepository ;
    @Autowired
    private TemplateInspectionItemRepository templateInspectionItemRepository;
    @Autowired
    private InspectionMasterValueService inspectionMasterValueService;
    @Autowired
    private InspectionItemValueService inspectionItemValueService;
    @Autowired
    private UserService userService;

    @Autowired
    private InspectionMasterValueRepository inspectionMasterValueRepository;

    @Autowired
    private InspectionItemValueRepository inspectionItemValueRepository;
    @Autowired
    private BatchPlanRepository batchPlanRepository;
    @Autowired
    private BatchProductRepository batchProductRepository;

    @Override
    public Page<InspectionTaskEx> getInspectionTaskByPage(PageEntity pageEntity) {
            Pageable pageable = PageRequest.of(
            pageEntity.getCurrent() -1,
            pageEntity.getPageSize());
            Page<InspectionTask> page = inspectionTaskRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
                    List<Predicate> list = new ArrayList<>();
                    Predicate pre1 =   JpaQueryBuilder.getPredicate(root, pageEntity.getFilters(), criteriaBuilder);
                    list.add(pre1);
                    Predicate pre2 = criteriaBuilder.equal(root.get(InspectionTask_.delete), 0); //过滤为0
                    list.add(pre2);
                    Predicate[] p = new Predicate[list.size()];
                    List<Order> orders = new ArrayList<>();
                    if(pageEntity.getSorters() != null && pageEntity.getSorters().size() > 0) {
                        orders = JpaSortBuilder.getPredicate(root, pageEntity.getSorters(), criteriaBuilder);
                        criteriaQuery.orderBy(orders);
                    } else {
                        criteriaQuery.orderBy(criteriaBuilder.desc(root.get(InspectionTask_.createTime).as(Date.class)));
                    }
                    return  criteriaBuilder.and(list.toArray(p));
                    }
                    , pageable);
            Page<InspectionTaskEx> page1 = page.map(inspectionTaskExMapper::toEntity);
        Page<InspectionTaskEx> map = page1.map(new Function<InspectionTaskEx, InspectionTaskEx>() {
            @Override
            public InspectionTaskEx apply(InspectionTaskEx inspectionTaskEx) {
                WorkOrderInfor workOrderInfor = workOrderInforRepository.findWorkOrderInforByWoAndDelete(inspectionTaskEx.getWo(), 0);
                if (workOrderInfor==null) {
                    inspectionTaskEx.setBatchProductCode(null);
                } else {
                    inspectionTaskEx.setBatchProductCode(workOrderInfor.getBatchProductCode());
                }
                return inspectionTaskEx;
            }
        });
        return map;

    }

    @Override
    public void addInspectionTask(InspectionTaskDto inspectionTaskDto) {
            InspectionTask result = inspectionTaskRepository.findInspectionTaskByIdAndDelete(inspectionTaskDto.getId(), 0);
            if(ObjectUtil.isNotEmpty(result)) {
                throw new BeadminException("InspectionTask不存在,请重新查询");
            }
            InspectionTask inspectionTask = inspectionTaskMapper.toEntity(inspectionTaskDto);
            inspectionTaskRepository.save(inspectionTask);
    }

    @Override
    public void updateInspectionTask(InspectionTaskDto inspectionTaskDto) {
            InspectionTask inspectionTask = inspectionTaskRepository.findInspectionTaskById(inspectionTaskDto.getId());
            inspectionTask = inspectionTaskMapper.toEntity(inspectionTaskDto);
            inspectionTaskRepository.save(inspectionTask);
    }


    @Override
    public void delInspectionTask(String id) {
        InspectionTask inspectionTask = inspectionTaskRepository.findInspectionTaskById(id);
        inspectionTask.setDelete(1);
        inspectionTaskRepository.save(inspectionTask);
    }

    @Override
    public void delInspectionTasks (List<String> ids) { }

    /**
     * 生成自检单
     *
     * @param productManufactInfor
     * @param template
     */
    @Override
    public InspectionTask generateInspectionTask(ProductManufactInfor productManufactInfor, InspectionTemplate template) {
        BatchProduct batchProduct = batchProductRepository.findBatchProductByIdAndDelete(productManufactInfor.getBatchProductId(), 0);
        BatchPlan batchPlan = batchPlanRepository.findBatchPlanByIdAndDelete(batchProduct.getBatchPlanId(), 0);
        WorkOrderInfor workOrderInfor = workOrderInforRepository.findWorkOrderInforByBatchProductIdAndDelete(batchProduct.getId(), 0);
        Info info = infoRepository.findInfoByIdAndDelete(batchProduct.getInfoId(), 0);
        InspectionTask inspectionTask = new InspectionTask();
        inspectionTask.setInspectionTemplateId(template.getId());
//        inspectionTask.setInspectTime(DateUtil.transDateFormat(new Date()));
        inspectionTask.setWo(workOrderInfor.getWo());
        inspectionTask.setProjectName(info.getProjectName());
        inspectionTask.setProjectCode(info.getProjectCode());
        inspectionTask.setInfoId(info.getId());
        inspectionTask.setBatchPlanId(batchPlan.getId());
        inspectionTask.setTemplateName(template.getName());
        inspectionTask.setCurrentBatch(batchPlan.getCurrentBatch());
        inspectionTask.setBatchCount(batchPlan.getBatchCount());
        inspectionTask.setType(template.getType());
        inspectionTask.setProcessId(productManufactInfor.getId());
        InspectionTask save = inspectionTaskRepository.save(inspectionTask);
        // 生成模板对应的每个检验项和对应值
        // 生成自定义项目值
        inspectionMasterValueService.generateInspectionMasterValue(save,template);
        // 生成检验记录表检验项目值
        inspectionItemValueService.generateInspectionItemValue(save,template);
        return inspectionTask;





    }

    public void generateInspectionTask(InspectionTask inspectionTask) {
        ProductManufactInfor productManufactById = productManufactInforService.getProductManufactById(inspectionTask.getProcessId());
        InspectionTemplate inspectionTemplateById = inspectionTemplateService.getInspectionTemplateById(inspectionTask.getInspectionTemplateId());
        ProductSelfCheckInfor productSelfCheckInforByProcessIdAndDelete = productSelfCheckInforRepository.findProductSelfCheckInforByProcessIdAndDelete(productManufactById.getId(), 0);
        InspectionTask inspectionTask1 = generateInspectionTask(productManufactById, inspectionTemplateById);
        productSelfCheckInforByProcessIdAndDelete.setInspectionTaskId(inspectionTask1.getId());

    }

    /**
     * 生成终检单
     *
     * @param template
     */
    @Override
    public InspectionTask generateFinishInspectionTask(WorkOrderInfor workOrderInfor, InspectionTemplate template) {
        BatchProduct batchProduct = batchProductRepository.findBatchProductByIdAndDelete(workOrderInfor.getBatchProductId(), 0);
        BatchPlan batchPlan = batchPlanRepository.findBatchPlanByIdAndDelete(batchProduct.getBatchPlanId(), 0);
        Info info = infoRepository.findInfoByIdAndDelete(batchProduct.getInfoId(), 0);
        InspectionTask inspectionTask = new InspectionTask();
        inspectionTask.setInspectionTemplateId(template.getId());
//        inspectionTask.setInspectTime(DateUtil.transDateFormat(new Date()));
        inspectionTask.setWo(workOrderInfor.getWo());
        inspectionTask.setProjectName(info.getProjectName());
        inspectionTask.setProjectCode(info.getProjectCode());
        inspectionTask.setInfoId(info.getId());
        inspectionTask.setBatchPlanId(batchPlan.getId());
        inspectionTask.setTemplateName(template.getName());
        inspectionTask.setCurrentBatch(batchPlan.getCurrentBatch());
        inspectionTask.setBatchCount(batchPlan.getBatchCount());
        inspectionTask.setType(template.getType());
        inspectionTask.setProcessId("-");
        InspectionTask save = inspectionTaskRepository.save(inspectionTask);
        // 生成模板对应的每个检验项和对应值
        // 生成自定义项目值
        inspectionMasterValueService.generateInspectionMasterValue(save,template);
        // 生成检验记录表检验项目值
        inspectionItemValueService.generateInspectionItemValue(save,template);
        return inspectionTask;

//        return null;
    }

    /**
     * 生成交检单
     *
     * @param batchPlan
     * @param template
     */
    @Override
    public InspectionTask generateSubmissionInspectionTask(BatchPlan batchPlan, InspectionTemplate template) {
        Info info = infoRepository.findInfoByIdAndDelete(batchPlan.getInfoId(), 0);
        InspectionTask inspectionTask = new InspectionTask();
        inspectionTask.setInspectionTemplateId(template.getId());
//        inspectionTask.setInspectTime(DateUtil.transDateFormat(new Date()));
        inspectionTask.setBatchPlanId(batchPlan.getId());
        inspectionTask.setProjectName(info.getProjectName());
        inspectionTask.setProjectCode(info.getProjectCode());
        inspectionTask.setInfoId(info.getId());
        inspectionTask.setBatchPlanId(batchPlan.getId());
        inspectionTask.setTemplateName(template.getName());
        inspectionTask.setCurrentBatch(batchPlan.getCurrentBatch());
        inspectionTask.setBatchCount(batchPlan.getBatchCount());
        inspectionTask.setType(template.getType());
        inspectionTask.setProcessId("-");
        InspectionTask save = inspectionTaskRepository.save(inspectionTask);
        // 生成模板对应的每个检验项和对应值
        // 生成自定义项目值
        inspectionMasterValueService.generateInspectionMasterValue(save,template);
        // 生成检验记录表检验项目值
        inspectionItemValueService.generateInspectionItemValue(save,template);
        return inspectionTask;
    }

    /**
     * 根据检验单id获取检验单详细内容
     *
     * @param taskId
     * @return
     */
    @Override
    public InspectionInfoAllEx getInspectionTaskById(String taskId) {
        InspectionTask inspectionTask = inspectionTaskRepository.findInspectionTaskByIdAndDelete(taskId, 0);
        if (inspectionTask==null) throw new BeadminException("未找到该任务单");
        // 找到该执行单对应的模板文件
        InspectionTemplate template = inspectionTemplateRepository.findInspectionTemplateByIdAndDelete(inspectionTask.getInspectionTemplateId(),0);
        if (template == null) {
            throw new BeadminException("未找到该检验单的模板");
        }
        List<InspectionCostomValueEx> inspectionCostomValueExList = new ArrayList<>();
        List<InspectionItemEx> inspectionItemExList = new ArrayList<>();
        // 该检验单对应的自定义项
        for (InspectionMasterValue inspectionMasterValue : inspectionMasterValueRepository.findInspectionMasterValuesByInspectionTaskIdAndDelete(taskId, 0)) {
            // 返回给前端的字段
            InspectionCostomValueEx inspectionCostomValueEx = new InspectionCostomValueEx();
            InspectionTemplateMasterItem inspectionTemplateMasterItem = inspectionTemplateMasterItemRepository.findInspectionTemplateMasterItemById(inspectionMasterValue.getTemplateCustomItemId());
            if (inspectionTemplateMasterItem == null) {
//                throw new BeadminException("未找到对应的自定义项");
                continue;
            }
            inspectionCostomValueEx.setTemplateCustomItemId(inspectionMasterValue.getTemplateCustomItemId());
            inspectionCostomValueEx.setTemplateCustomItemValue(inspectionMasterValue.getTemplateCustomItemValue());
            inspectionCostomValueEx.setId(inspectionMasterValue.getId());
            inspectionCostomValueEx.setName(inspectionTemplateMasterItem.getName());
            inspectionCostomValueEx.setValueType(inspectionTemplateMasterItem.getValueType());
            inspectionCostomValueEx.setPosition(inspectionTemplateMasterItem.getPosition());
            inspectionCostomValueEx.setSortId(inspectionTemplateMasterItem.getSortId());
            inspectionCostomValueEx.setMemo(inspectionTemplateMasterItem.getMemo());
            inspectionCostomValueExList.add(inspectionCostomValueEx);
        }
        // 该检验单对应的每一项
        for (InspectionItemValue inspectionItemValue : inspectionItemValueRepository.findInspectionItemValuesByInspectionTaskIdAndDelete(taskId, 0)) {
            TemplateInspectionItem templateInspectionItem = templateInspectionItemRepository.findTemplateInspectionItemById(inspectionItemValue.getTemplateInspectionItemId());
            InspectionItemEx inspectionItemEx = new InspectionItemEx(
                    inspectionItemValue.getId(),
                    templateInspectionItem.getId(),
                    templateInspectionItem.getOptionType(),
                    inspectionItemValue.getRightValue(),
                    inspectionItemValue.getMultiValue(),
                    inspectionItemValue.getMultiDesValue(),
                    inspectionItemValue.getDescValue(),
                    templateInspectionItem.getItemName(),
                    templateInspectionItem.getInspectionMethod(),
                    templateInspectionItem.getSortId(),
                    templateInspectionItem.getInspectionTemplateId(),
                    templateInspectionItem.getIsDetailDes(),
                    templateInspectionItem.getIsExtendDes(),
                    templateInspectionItem.getDescOption(),
                    templateInspectionItem.getRightOption(),
                    templateInspectionItem.getMemo()
            );
            inspectionItemExList.add(inspectionItemEx);

        }

        return new InspectionInfoAllEx(inspectionTask,inspectionCostomValueExList,inspectionItemExList);
    }

    /**
     * 根据工序Id获取检验单详细内容
     *
     * @param processId
     * @return
     */
    @SneakyThrows
    @Override
    public InspectionInfoAllEx getInspectionTaskValueByProcessId(String processId)  {

        ProductSelfCheckInfor productSelfCheckInforByProcessIdAndDelete = productSelfCheckInforRepository.findProductSelfCheckInforByProcessIdAndDelete(processId, 0);
        if (productSelfCheckInforByProcessIdAndDelete == null) {
            return null;
        }
        return getInspectionTaskById(productSelfCheckInforByProcessIdAndDelete.getInspectionTaskId());


        // 需要获取未完成的那个检查单
//        List<InspectionTask> taskList = inspectionTaskRepository.findInspectionTasksByProcessIdAndStateAndDelete(processId,0, 0);
//        InspectionInfoAllEx inspectionTaskById = null;
//        if (taskList.size()!=0){
//            inspectionTaskById = getInspectionTaskById(taskList.get(0).getId());
//        } else { // 如果未找到说明没有单子生成，  或者是说该过程不需要生成
//            throw new BeadminException("未找到该工序的自检单");
//        }
//
//        return inspectionTaskById;
    }

    /**
     * 暂存检验单
     * @param inspectionInfoAllDto
     */
    @Override
    public void stagingInspectionTask(HttpServletRequest request,InspectionInfoAllDto inspectionInfoAllDto) {
        saveInspectionTask(request,inspectionInfoAllDto,false);
    }

//    @Override
//    public InspectionTask getInspectionTaskByBatchProductAndProcessType(String batchProductId, String processType) {
//        inspectionTaskRepository.findInspectionTasksByProcessIdAndDelete()
//
//        return null;
//    }

    /**
     * 提交检验单
     *
     * @param inspectionInfoAllDto
     */
    @Override
    public void submitInspectionTask(HttpServletRequest request, InspectionInfoAllDto inspectionInfoAllDto) {
        saveInspectionTask(request,inspectionInfoAllDto,true);
    }

    /**
     * 完成检验单
     *
     * @param id
     */
    @Override
    public void finishInspectionTask(HttpServletRequest request,String id) {
        InspectionTask inspectionTaskByIdAndDelete = inspectionTaskRepository.findInspectionTaskByIdAndDelete(id, 0);
        inspectionTaskByIdAndDelete.setInspection(1); //这里的完成一定是合格的， 所以不会额外生成检验单的。

        finishInspectionTask(request,inspectionTaskByIdAndDelete);
    }

    public void finishInspectionTask(HttpServletRequest request,InspectionTask inspectionTask) {
//        InspectionTask inspectionTaskByIdAndDelete = inspectionTaskRepository.findInspectionTaskByIdAndDelete(id, 0);
        if (inspectionTask.getInspection() == -1 ) { // 不合格
            // 重新生成新的检验单绑定在自检单中，
            generateInspectionTask(inspectionTask);
            // 但如果是终检和交检 -- 直接跟据状态去查找。
        }
        // 合格或者让步接收， 就可以直接进入下个阶段
        UserEx userEx = userService.viewBaseInfo(request);
        inspectionTask.setFinisher(userEx.getName());
        inspectionTask.setFinishedTime(new Date());
        inspectionTaskRepository.save(inspectionTask);
    }
    @Override
    public InspectionTask getInspectionTaskByProductQualityId(String productQualityId) {
        if(productQualityId==null) throw new BeadminException("未指定入厂检id");
        return inspectionTaskRepository.findInspectionTaskByProductQualityIdAndDelete(productQualityId,0);
    }

    /**
     * 保存检验单
     *
     * @param inspectionInfoAllDto
     */
    public void saveInspectionTask(HttpServletRequest request,InspectionInfoAllDto inspectionInfoAllDto, boolean isPersist) {
        InspectionTask inspectionTask = inspectionInfoAllDto.getInspectionTask();
        UserEx userEx = userService.viewBaseInfo(request);
        for (InspectionItemDto inspectionItemDto : inspectionInfoAllDto.getInspectionItemDtoList()) {
            InspectionItemValue itemValue = inspectionItemValueRepository.findInspectionItemValueByInspectionTaskIdAndTemplateInspectionItemIdAndDelete(inspectionTask.getId(),inspectionItemDto.getTemplateInspectionItemId(), 0);
            itemValue.setRightValue(inspectionItemDto.getRightValue());
            itemValue.setMultiValue(inspectionItemDto.getMultiValue());
            itemValue.setMultiDesValue(inspectionItemDto.getMultiDesValue());
            itemValue.setDescValue(inspectionItemDto.getDescValue());
            inspectionItemValueRepository.save(itemValue);
        }

        for (InspectionCostomValueDto inspectionCostomValueDto : inspectionInfoAllDto.getInspectionCostomValueDtoList()) {
            InspectionMasterValue masterValue = inspectionMasterValueRepository.findInspectionMasterValueByInspectionTaskIdAndTemplateCustomItemIdAndDelete(inspectionTask.getId(),inspectionCostomValueDto.getTemplateCustomItemId(), 0);
            if (inspectionCostomValueDto.getName().equals("交捡日期")) {
                masterValue.setTemplateCustomItemValue(DateUtil.transDateFormatToString(new Date()));
            } else if (inspectionCostomValueDto.getName().equals("操作者")) {
                masterValue.setTemplateCustomItemValue(userEx.getName());
            } else {
                masterValue.setTemplateCustomItemValue(inspectionCostomValueDto.getTemplateCustomItemValue());
            }

            inspectionMasterValueRepository.save(masterValue);
        }
        InspectionTask task = inspectionTaskRepository.findInspectionTaskByIdAndDelete(inspectionTask.getId(), 0);
        task.setMemo(inspectionTask.getMemo());
        task.setInspector(userEx.getName());
        if (isPersist) {
            task.setState(1);
            // 判断 自定义项和检验项，每一项，的value不可为空
            checkNotNullValue(task);
//            inspectionTaskRepository.save(task);\
            // 检验是否合格 合格就直接直接完成， // 不合格就重新生成一个检验单
            finishInspectionTask(request,task);
        } else {
            inspectionTaskRepository.save(task);
        }

    }

    /**
     * 检验值是否为空
     * @param task
     */
    private void checkNotNullValue(InspectionTask task) {
        InspectionTemplate templateById = inspectionTemplateService.getInspectionTemplateById(task.getInspectionTemplateId());
        for (InspectionTemplateMasterItem inspectionTemplateMasterItem : inspectionTemplateMasterItemRepository.findInspectionTemplateMasterItemByInspectionTemplateIdAndDelete(templateById.getId(), 0)) {
            InspectionMasterValue masterValue = inspectionMasterValueRepository.findInspectionMasterValueByInspectionTaskIdAndTemplateCustomItemIdAndDelete(task.getId(), inspectionTemplateMasterItem.getId(), 0);
            // 预留自定义项的判断


        }
        for (TemplateInspectionItem templateInspectionItem : templateInspectionItemRepository.findTemplateInspectionItemByInspectionTemplateIdAndDelete(templateById.getId(), 0)) {
            InspectionItemValue itemValue = inspectionItemValueRepository.findInspectionItemValueByInspectionTaskIdAndTemplateInspectionItemIdAndDelete(task.getId(), templateInspectionItem.getId(), 0);
            if (itemValue == null) {
                throw new BeadminException("未找到题目"+templateInspectionItem.getSortId()+"的答案");
            }
            // 检查选项是否为空 ， 先注释掉，。。。。  前面没有写好
//            switch (templateInspectionItem.getOptionType()) {
//                case "单选":
//                    if (ObjectUtil.isEmpty(itemValue.getRightValue()))
//                        throw new BeadminException("题目"+templateInspectionItem.getSortId()+"没有选择，请选择");
//                    break;
//                case "多选":
//                    if (ObjectUtil.isEmpty(itemValue.getMultiValue()) && ObjectUtil.isEmpty(itemValue.getMultiDesValue()))
//                        throw new BeadminException("题目"+templateInspectionItem.getSortId()+"没有填写，请选择/或者填写其他内容");
//                    break;
//                case "填空":
//                    if (ObjectUtil.isEmpty(itemValue.getDescValue()))
//                        throw new BeadminException("题目"+templateInspectionItem.getSortId()+"没有填写，请填写内容");
//                    break;
//                case "描述":
//                    if (ObjectUtil.isEmpty(itemValue.getDescValue()))
//                        throw new BeadminException("题目"+templateInspectionItem.getSortId()+"没有填写，请填写内容");
//                    break;
//            }
        }


    }

}